/*
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at 
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  
 */

using System;
using java = biz.ritter.javapi;
using org.apache.commons.collections;

namespace org.apache.commons.collections.iterators
{

    /**
     * Converts an iterator into a list iterator by caching the returned entries.
     * <p>
     * The <code>ListIterator</code> interface has additional useful methods
     * for navigation - <code>previous()</code> and the index methods.
     * This class allows a regular <code>Iterator</code> to behave as a
     * <code>ListIterator</code>. It achieves this by building a list internally
     * of as the underlying iterator is traversed.
     * <p>
     * The optional operations of <code>ListIterator</code> are not supported.
     * <p>
     * This class implements ResettableListIterator from Commons Collections 3.2.
     *
     * @since Commons Collections 2.1
     * @version $Revision: 7135 $ $Date: 2011-06-04 20:58:43 +0200 (Sa, 04. Jun 2011) $
     *
     * @author Morgan Delagrange
     * @author Stephen Colebourne
     */
    public class ListIteratorWrapper : ResettableListIterator
    {

        /** Message used when remove, set or add are called. */
        private static readonly String UNSUPPORTED_OPERATION_MESSAGE =
            "ListIteratorWrapper does not support optional operations of ListIterator.";

        /** The underlying iterator being decorated. */
        private readonly java.util.Iterator<Object> iterator;
        /** The list being used to cache the iterator. */
        private readonly java.util.List<Object> list = new java.util.ArrayList<Object>();

        /** The current index of this iterator. */
        private int currentIndex = 0;
        /** The current index of the wrapped iterator. */
        private int wrappedIteratorIndex = 0;

        // Constructor
        //-------------------------------------------------------------------------
        /**
         * Constructs a new <code>ListIteratorWrapper</code> that will wrap
         * the given iterator.
         *
         * @param iterator  the iterator to wrap
         * @throws NullPointerException if the iterator is null
         */
        public ListIteratorWrapper(java.util.Iterator<Object> iterator)
            : base()
        {
            if (iterator == null)
            {
                throw new java.lang.NullPointerException("Iterator must not be null");
            }
            this.iterator = iterator;
        }

        // ListIterator interface
        //-------------------------------------------------------------------------
        /**
         * Throws {@link UnsupportedOperationException}.
         *
         * @param obj  the object to add, ignored
         * @throws UnsupportedOperationException always
         */
        public void add(Object obj)
        {//throws UnsupportedOperationException {
            throw new java.lang.UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
        }

        /**
         * Returns true if there are more elements in the iterator.
         *
         * @return true if there are more elements
         */
        public bool hasNext()
        {
            if (currentIndex == wrappedIteratorIndex)
            {
                return iterator.hasNext();
            }
            return true;
        }

        /**
         * Returns true if there are previous elements in the iterator.
         *
         * @return true if there are previous elements
         */
        public bool hasPrevious()
        {
            if (currentIndex == 0)
            {
                return false;
            }
            return true;
        }

        /**
         * Returns the next element from the iterator.
         *
         * @return the next element from the iterator
         * @throws NoSuchElementException if there are no more elements
         */
        public Object next()
        {//throws NoSuchElementException {
            if (currentIndex < wrappedIteratorIndex)
            {
                ++currentIndex;
                return list.get(currentIndex - 1);
            }

            Object retval = iterator.next();
            list.add(retval);
            ++currentIndex;
            ++wrappedIteratorIndex;
            return retval;
        }

        /**
         * Returns in the index of the next element.
         *
         * @return the index of the next element
         */
        public int nextIndex()
        {
            return currentIndex;
        }

        /**
         * Returns the the previous element.
         *
         * @return the previous element
         * @throws NoSuchElementException  if there are no previous elements
         */
        public Object previous()
        {//throws NoSuchElementException {
            if (currentIndex == 0)
            {
                throw new java.util.NoSuchElementException();
            }
            --currentIndex;
            return list.get(currentIndex);
        }

        /**
         * Returns the index of the previous element.
         *
         * @return  the index of the previous element
         */
        public int previousIndex()
        {
            return currentIndex - 1;
        }

        /**
         * Throws {@link UnsupportedOperationException}.
         *
         * @throws UnsupportedOperationException always
         */
        public void remove()
        {//throws UnsupportedOperationException {
            throw new java.lang.UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
        }

        /**
         * Throws {@link UnsupportedOperationException}.
         *
         * @param obj  the object to set, ignored
         * @throws UnsupportedOperationException always
         */
        public void set(Object obj)
        {//throws UnsupportedOperationException {
            throw new java.lang.UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
        }

        // ResettableIterator interface
        //-------------------------------------------------------------------------
        /**
         * Resets this iterator back to the position at which the iterator
         * was created.
         *
         * @since Commons Collections 3.2
         */
        public void reset()
        {
            currentIndex = 0;
        }

    }
}